package com.itheima.stock.service.impl;

import com.alibaba.excel.EasyExcel;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.itheima.stock.common.domain.*;
import com.itheima.stock.config.StockInfoConfig;
import com.itheima.stock.mapper.*;
import com.itheima.stock.pojo.StockBusiness;
import com.itheima.stock.service.StockService;
import com.itheima.stock.utils.DateTimeUtil;
import com.itheima.stock.vo.resp.BusinessRespVo;
import com.itheima.stock.vo.resp.CodeRespVo;
import com.itheima.stock.vo.resp.PageResult;
import com.itheima.stock.vo.resp.R;
import lombok.extern.slf4j.Slf4j;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.*;
import java.util.stream.Collectors;

@Service("stockService")
@Slf4j
public class StockServiceImpl implements StockService {
    /**
     * 股票业务映射器
     */
    @Autowired
    private StockBusinessMapper stockBusinessMapper;

    @Autowired
    private StockInfoConfig stockInfoConfig;


    @Autowired
    private StockMarketIndexInfoMapper stockMarketIndexInfoMapper;

    @Autowired
    private StockBlockRtInfoMapper stockBlockRtInfoMapper;

    @Autowired
    private StockRtInfoMapper stockRtInfoMapper;

    @Autowired
    private StockOuterMarketIndexInfoMapper stockOuterMarketIndexInfoMapper;



    /**
     * 查询股票主营业务数据
     *
     * @return {@link List}<{@link StockBusiness}>
     */
    @Override
    public List<StockBusiness> getAll() {

        return stockBusinessMapper.getAll();
    }

    /**
     * 获取最新国内A股大盘信息(上证+深证)
     *
     * @return {@link R}<{@link List}<{@link InnerMarketDomain}>>
     */
    @Override
    public R<List<InnerMarketDomain>> getInnerMarketInfos() {
        //获取最近的一次股票交易时间点
        Date lastDate = DateTimeUtil.getLastDate4Stock(DateTime.now()).toDate();
        //目前还没有实现股票实时采集，先临时指定一个时间点
      //  log.info("大盘有效时间：{}" , lastDate);
        lastDate = DateTime.parse("2021-12-28 09:31:00",
                DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        //获取国内A股大盘的id集合
        List<String> inners = stockInfoConfig.getInner();
        //将获取的java Date传入接口
        List<InnerMarketDomain> list = stockMarketIndexInfoMapper.getInnerMarketInfosByCodesAndTime(inners, lastDate);
        //返回查询结果
        return R.ok(list);
    }

    /**
     * 需求说明: 获取沪深两市板块最新数据，以交易总金额降序查询，取前10条数据
     *
     * @return
     */
    @Override
    public R<List<StockBlockDomain>> sectorAllLimit() {
        //获取最近的一次股票交易时间点
        Date lastDate = DateTimeUtil.getLastDate4Stock(DateTime.now()).toDate();

        //目前还没有实现股票实时采集，先临时指定一个时间点
        lastDate = DateTime.parse("2021-12-21 09:30:00",
                DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        //调用持久层方法获取数据
        Integer order = 10;
        List<StockBlockDomain> infos = stockBlockRtInfoMapper.sectorAllLimit(lastDate, order);
        return R.ok(infos);
    }

    /**
     * 沪深两市个股涨幅分时行情数据查询，以时间顺序和涨幅查询前10条数据
     *
     * @return
     */
    @Override
    public R<List<StockUpdownDomain>> stockIncreaseLimit() {
        //获取最近的一次股票交易时间点
        Date lastDate = DateTimeUtil.getLastDate4Stock(DateTime.now()).toDate();
        //目前还没有实现股票实时采集，先临时指定一个时间点
       lastDate = DateTime.parse("2022-05-13 15:00:00",
             DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        int num = 10;
        List<StockUpdownDomain> infos = stockRtInfoMapper.stockIncreaseLimit(lastDate, num);
        return R.ok(infos);
    }

    /**
     * 个股行情列表分页查询
     *
     * @param page     页面
     * @param pageSize 页面大小
     * @return {@link R}<{@link PageResult}<{@link StockUpdownDomain}>>
     */
    @Override
    public R<PageResult<StockUpdownDomain>> stockPageByTimeAndUpDown(Integer page, Integer pageSize) {
        //设置分页参数
        PageHelper.startPage(page, pageSize);
        //1.获取最近最新的一次股票有效交易时间点（精确分钟）
        Date curDate = DateTimeUtil.getLastDate4Stock(DateTime.now()).toDate();
        //因为对于当前来说，我们没有实现股票信息实时采集的功能，所以最新时间点下的数据
        //在数据库中是没有的，所以，先临时指定一个假数据,后续注释掉该代码即可
          curDate = DateTime.parse("2022-05-13 15:00:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        //调用持久层方法查询数据
        List<StockUpdownDomain> infos = stockRtInfoMapper.getAllStockUpDownByTime(curDate);
        //封装PageHelper分页对象 因为前端不需要更加丰富的分页数据，仅仅需要局部的几个字段信息
        //原则：严格遵循前后端接口的约定，不要多传参数
        PageInfo<StockUpdownDomain> pageInfo = new PageInfo<>(infos);
        PageResult<StockUpdownDomain> pageResult = new PageResult<>(pageInfo);
        return R.ok(pageResult);
    }

    /**
     * 功能描述：沪深两市涨跌停分时行情数据查询，查询T日每分钟的涨跌停数据（T：当前股票交易日）
     * 查询每分钟的涨停和跌停的数据的同级；
     * 如果不在股票的交易日内，那么就统计最近的股票交易下的数据
     * map:
     * upList:涨停数据统计
     * downList:跌停数据统计
     *
     * @return
     */
    @Override
    public R<Map> upDownCount() {
        //获取有效时间点
        DateTime avableTimePoint = DateTimeUtil.getLastDate4Stock(DateTime.now());
        //根据有效的时间点获取对应日期的开盘和收盘日期
        Date openTime = DateTimeUtil.getOpenDate(avableTimePoint).toDate();
        Date closeTime = DateTimeUtil.getCloseDate(avableTimePoint).toDate();
        //伪数据
          openTime = DateTime.parse("2021-12-19 09:30:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
          closeTime = DateTime.parse("2021-12-19 15:00:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        //2.查询涨停的统计数据
        List<Map> upList = stockRtInfoMapper.getStockUpDownCount(openTime, closeTime, 1);
        //3.查询跌停的统计数据
        List<Map> downList = stockRtInfoMapper.getStockUpDownCount(openTime, closeTime, 0);
        //4.组装map：将涨停和跌停的数据组装到map中
        HashMap<String, List> map = new HashMap<>();
        map.put("upList", upList);
        map.put("downList", downList);
        //5.返回结果
        return R.ok(map);
    }

    /**
     * 将指定页的股票数据导出到excel表下
     *
     * @param response 响应
     * @param page     页面
     * @param pageSize 页面大小
     */
    @Override
    public void stockExport(HttpServletResponse response, Integer page, Integer pageSize) {
        //1.设置响应数据的类型:excel
        try {
            response.setContentType("application/vnd.ms-excel");
            //2.设置响应数据的编码格式
            response.setCharacterEncoding("utf-8");
            //3.设置默认的文件名称
            // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
            String fileName = URLEncoder.encode("stockRt", "UTF-8");
            //设置默认文件名称
            response.setHeader("content-disposition", "attachment;filename=" + fileName + ".xlsx");
            //获取指定页面下的股票涨幅信息
            //设置分页参数
            PageHelper.startPage(page, pageSize);
            //1.获取最近最新的一次股票有效交易时间点（精确分钟）
            Date curDate = DateTimeUtil.getLastDate4Stock(DateTime.now()).toDate();
            //因为对于当前来说，我们没有实现股票信息实时采集的功能，所以最新时间点下的数据
            //在数据库中是没有的，所以，先临时指定一个假数据,后续注释掉该代码即可
            curDate = DateTime.parse("2022-05-13 15:00:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
            //调用持久层方法查询数据
            List<StockUpdownDomain> infos = stockRtInfoMapper.getAllStockUpDownByTime(curDate);
            //响应
            EasyExcel.write(response.getOutputStream(), StockUpdownDomain.class)
                    .sheet("股票信息")
                    .doWrite(infos);
        } catch (IOException e) {
            e.printStackTrace();
            log.info("当前导出数据异常，当前页：{},每页条数：{},异常信息：{}", page, pageSize, e.getMessage());
        }
    }

    /**
     * 功能描述：统计国内A股大盘T日和T-1日成交量对比功能（成交量为沪市和深市成交量之和）
     * map结构示例：
     * {
     * "volList": [{"count": 3926392,"time": "202112310930"},......],
     * "yesVolList":[{"count": 3926392,"time": "202112310930"},......]
     * }
     *
     * @return
     */
    @Override
    public R<Map<String, List>> stockTradeVol4InnerMarket() {
        //1.获取T日和T-1日的开始时间和结束时间
        //1.1 获取最近股票有效交易时间点--T日时间范围
        DateTime lastDateTime = DateTimeUtil.getLastDate4Stock(DateTime.now());
        DateTime openDateTime = DateTimeUtil.getOpenDate(lastDateTime);
        //转化成java中Date,这样jdbc默认识别
        Date startTime4T = openDateTime.toDate();
        Date endTime4T = lastDateTime.toDate();
        //TODO  mock数据
          startTime4T = DateTime.parse("2022-01-03 09:30:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
          endTime4T = DateTime.parse("2022-01-03 14:40:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();

        //1.2 获取T-1日的区间范围
        //获取lastDateTime的上一个股票有效交易日
        DateTime preLastDateTime = DateTimeUtil.getPreviousTradingDay(lastDateTime);
        DateTime preOpenDateTime = DateTimeUtil.getOpenDate(preLastDateTime);
        //转化成java中Date,这样jdbc默认识别
        Date startTime4PreT = preOpenDateTime.toDate();
        Date endTime4PreT = preLastDateTime.toDate();
        //TODO  mock数据
         startTime4PreT = DateTime.parse("2022-01-02 09:30:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
          endTime4PreT = DateTime.parse("2022-01-02 14:40:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();

        //2.获取上证和深证的配置的大盘id
        //2.1 获取大盘的id集合
        List<String> markedIds = stockInfoConfig.getInner();
        //3.分别查询T日和T-1日的交易量数据，得到两个集合
        //3.1 查询T日大盘交易统计数据
        List<Map> data4T = stockMarketIndexInfoMapper.getStockTradeVol(markedIds, startTime4T, endTime4T);

        //3.2 查询T-1日大盘交易统计数据
        List<Map> data4PreT = stockMarketIndexInfoMapper.getStockTradeVol(markedIds, startTime4PreT, endTime4PreT);

        //4.组装响应数据
        HashMap<String, List> info = new HashMap<>();
        info.put("volList", data4T);
        info.put("yesVolList", data4PreT);
        //5.返回数据
        return R.ok(info);
    }

    /**
     * 查询当前时间下股票的涨跌幅度区间统计功能
     * 如果当前日期不在有效时间内，则以最近的一个股票交易时间作为查询点
     *
     * @return
     */
    @Override
    public R<Map> stockUpDownScopeCount() {
        //1.获取当前时间下最近的一个股票交易时间 精确到秒
        DateTime avlDateTime = DateTimeUtil.getLastDate4Stock(DateTime.now());
        Date avlDate = avlDateTime.toDate();
        //TODO 后续删除 mock-data
         String mockDate = "20220106095500";
         avlDate = DateTime.parse(mockDate, DateTimeFormat.forPattern("yyyyMMddHHmmss")).toDate();
        //2.查询
        List<Map> maps = stockRtInfoMapper.stockUpDownScopeCount(avlDate);
        //获取去股票涨幅区间的集合
        List<String> upDownRange = stockInfoConfig.getUpDownRange();
        //将list集合下的字符串映射成Map对象
        List<Map> orderMap = upDownRange.stream().map(key -> {
            Optional<Map> title = maps.stream().filter(map -> key.equals(map.get("title"))).findFirst();
            //判断对应的map是否存在
            Map tmp = null;
            if (title.isPresent()) {
                tmp = title.get();
            } else {
                tmp = new HashMap();
                tmp.put("title", key);
                tmp.put("count", 0);
            }
            return tmp;
        }).collect(Collectors.toList());
        //3.组装data
        HashMap<String, Object> data = new HashMap<>();
        data.put("time", avlDateTime.toString("yyyy-MM-dd HH:mm:ss"));
        data.put("infos", orderMap);
        //返回响应数据
        return R.ok(data);
    }

    /**
     * 功能描述：查询单个个股的分时行情数据，也就是统计指定股票T日每分钟的交易数据；
     * 如果当前日期不在有效时间内，则以最近的一个股票交易时间作为查询时间点
     *
     * @param stockCode 股票编码
     * @return
     */
    @Override
    public R<List<Stock4MinuteDomain>> stockScreenTimeSharing(String stockCode) {
        //1.获取最新股票交易时间点和开盘时间点
        DateTime endDateTime = DateTimeUtil.getLastDate4Stock(DateTime.now());
        Date startDate = DateTimeUtil.getOpenDate(endDateTime).toDate();
        Date endDate = endDateTime.toDate();
        //mock data
           endDate = DateTime.parse("2021-12-30 14:30:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
         startDate = DateTime.parse("2021-12-30 09:30:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        //2.查询指定日期范围内的数据
        List<Stock4MinuteDomain> infos = this.stockRtInfoMapper.getStockSecondInfoByCodeAndTime(startDate, endDate, stockCode);
        //3.响应
        return R.ok(infos);
    }

    /**
     * 得到股票屏幕dk线
     *
     * @param stockCode 股票代码
     * @return {@link R}<{@link List}<{@link Stock4EvrDayDomain}>>
     */
    @Override
    public R<List<Stock4EvrDayDomain>> getStockScreenDkLine(String stockCode) {
        //1.获取日K线查询的时间范围
        DateTime endDateTime = DateTimeUtil.getLastDate4Stock(DateTime.now());
        Date endDate = endDateTime.toDate();
        Date startDate = endDateTime.minusDays(10).toDate();

        //mock data
         endDate = DateTime.parse("2022-01-06 14:25:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
         startDate = DateTime.parse("2022-01-01 09:30:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        //2.调用mapper查询
        List<Stock4EvrDayDomain> infos = this.stockRtInfoMapper.getStockEvyDayInfoByCodeAndTime(startDate, endDate, stockCode);
        return R.ok(infos);
    }

    /**
     * 查询国外大盘数据信息
     *
     * @return {@link R}<{@link OuterMarketDomain}>
     */
    @Override
    public R<List<OuterMarketDomain>> getOuterMarketInfos() {
        //获取有效时间点
        Date lastDate = DateTimeUtil.getLastDate4Stock(DateTime.now()).toDate();
        //Date date = lastDate.toDate();
        //目前还没有实现股票实时采集，先临时指定一个时间点
        //  log.info("外盘有效时间：{}" , lastDate);
        lastDate = DateTime.parse("2022-05-18 15:58:00",
                DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        //获取外盘的id集合
        List<String> outers = stockInfoConfig.getOuter();
        //定义显示条数
        Integer num = 4;
        //调用持久层方法查询数据信息
        List<OuterMarketDomain> result = stockOuterMarketIndexInfoMapper.getOuterMarketInfosByCodesAndTime(lastDate,outers,num);
        //返回数据
        return R.ok(result);
    }

    /**
     * 股票Code联想推荐功能
     *
     * @param code 代码
     * @return {@link R}<{@link List}<{@link CodeRespVo}>>
     */
    @Override
    public R<List<CodeRespVo>> getStockByCode(String code) {
        //调用持久层方法查询数据信息
        List<CodeRespVo> result = stockRtInfoMapper.getStockByCode(code);
        //响应数据
        return R.ok(result);
    }

    /**
     * 根据股票编码查询个股主营业务
     *
     * @param code 代码
     * @return {@link R}<{@link BusinessRespVo}>
     */
    @Override
    public R<BusinessRespVo> getStockAccountByCode(String code) {
        BusinessRespVo result = null;
        if (code!=null){
            //调用持久层方法查询数据信息
            result = stockBusinessMapper.getStockAccountByCode(code);
        }
        //响应数据
        return R.ok(result);
    }
    /**
     * 统计每周内的股票数据信息
     *
     * @param code 代码
     * @return {@link R}<{@link Map}>
     */
    @Override
    public R<List<Map>> getStockWeekDKLine(String code) {
        //调用持久层方法查询数据信息
       List<Map> result =  stockRtInfoMapper.getStockWeekDKLine(code);
        return R.ok(result);
    }
}
